iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 19
0
自我挑戰組

寫遊戲初體驗系列 第 19

Day 19 Texture & ResourceManager

  • 分享至 

  • xImage
  •  

封裝 Texture

我們要封裝 Texture 的目的與 Shader 相同,所以我們就趕緊開始封裝吧。

Texture 的封裝比較簡單。

class Texture2D {

public:
    Texture2D() = default;
    Texture2D(const std::string& path);
    ~Texture2D();

    uint32_t getWidth() const { return width_; }
    uint32_t getHeight() const { return height_; }

    void bind(uint32_t slot = 0) const;
    void unbind() const;

private:

    std::string path_;
    uint32_t width_;
    uint32_t height_;
    uint32_t textureID_;
};

一樣它需要一個屬於自己的 ID。

而我們在 construct 的時候一樣傳入我們影像的路徑。

Texture2D::Texture2D(const std::string& path) : path_(path){

    sf::Image image;
    if(!image.loadFromFile(path)) printf("[Texture2D] Error on loading image");

    // image.flipVertically();

    width_ = image.getSize().x;
    height_ = image.getSize().y;
    glCreateTextures(GL_TEXTURE_2D, 1, &textureID_);
    glBindTexture(GL_TEXTURE_2D, textureID_);
    glTextureStorage2D(textureID_, 1, GL_RGBA8, width_, height_);

    glTextureParameteri(textureID_, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTextureParameteri(textureID_, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    glTextureSubImage2D(textureID_, 0, 0, 0, width_, height_, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)image.getPixelsPtr());
    glBindTexture(GL_TEXTURE_2D, 0);
}

bind/unbind就一樣的簡單。

void Texture2D::bind(uint32_t slot) const {

    glBindTextureUnit(slot, textureID_);
}

void Texture2D::unbind() const{

    glBindTextureUnit(0, 0);
}

使用方法

Texture texture("picture.png");

ResourceManager

現在我們有 Texture 跟 Shader 的管理器了,但是他們仍需要寫一些 code 來初始化它。當然我們可以很輕鬆地將文件加載的功能寫入各自的功能當中,但這樣耦合性有點太高了。這兩個物件應該只關自己本身該關注的事情,而不是文件加載。

出於這個原因,我們需要更好的方法來實現文件加載。ResourceManager就是專門加載遊戲相關資源的管理器。

實作方法有很多種,這裡使用單利模式(Singleton)來實作。它將在整個遊戲中都能夠使用。

實作

在實作前,有時候會不知道怎麼寫比較好。
其實有個辦法,先想像你希望API用起來是如何。

像是我希望我的資源管理器用起來是這樣。

ResourceManager::loadShader("vShader.glsl", "fShader.glsl", "sprite");
auto& shader = ResourceManager::getShader("sprite");

ResourceManager::loadTexture("gardevoir.png", "gardevoir");
auto &texture = texture_ = ResourceManager::getTexture( "gardevoir");

我能夠輕易地將 vertexShader, fragmentShader 加載至資源管理器中,並且調用ResourceManager::getShader來獲得我的 Shader, Texture同理。

所以根據我的想像,我能夠輕易地將介面寫出來。

class ResourceManager {

public:

    static std::map<std::string, std::shared_ptr<Shader>> shader;
    static std::map<std::string, std::shared_ptr<Texture2D>> texture;

    static std::shared_ptr<Shader>& loadShader(const std::string& vShaderPath, const std::string& fShaderPath, std::string name);
    static std::shared_ptr<Shader>& getShader(std::string name);

    static std::shared_ptr<Texture2D>& loadTexture(const std::string& tPath, std::string name);
    static std::shared_ptr<Texture2D>& getTexture(std::string name);

    static void clear();

private:

    ResourceManager();
};

接著將它實作

std::map<std::string, std::shared_ptr<Shader>> ResourceManager::shader;
std::map<std::string, std::shared_ptr<Texture2D>> ResourceManager::texture;

std::shared_ptr<Shader>& ResourceManager::loadShader(const std::string& vShaderPath, const std::string& fShaderPath, std::string name) {

    shader[name] = std::make_shared<Shader>(vShaderPath.c_str(), fShaderPath.c_str());
    return shader[name];
}


std::shared_ptr<Shader>& ResourceManager::getShader(std::string name) {

    return shader[name];
}

std::shared_ptr<Texture2D>& ResourceManager::loadTexture(const std::string& tPath, std::string name) {

    texture[name] = std::make_shared<Texture2D>(tPath);
    return texture[name];
}

std::shared_ptr<Texture2D>& ResourceManager::getTexture(std::string name) {

    return texture[name];
}

void ResourceManager::clear() {

    shader.clear();
    texture.clear();
}

這樣就完成我們簡易的資源管理器啦!


上一篇
Day 18 Shader Class
下一篇
Day 20 Renderer 2D
系列文
寫遊戲初體驗30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言